from decimal import Decimal

import stripe
from django.conf import settings
from rest_framework import status
from rest_framework.exceptions import ValidationError
from rest_framework.response import Response

from apps.billing.models import ClientPayment, ClientInvoice
from apps.billing.types import ClientPaymentType, ClientInvoiceStatus
from apps.users.models import Provider

stripe.api_key = settings.STRIPE_SECRET_KEY
SMALLEST_CURRENCY_UNIT = Decimal(settings.SMALLEST_CURRENCY_UNIT)


def create_charge_by_stripe(user, price, data, pk, request):
    try:
        amount = int(price * SMALLEST_CURRENCY_UNIT)
        stripe_account_id = ''

        card_id = request.data.get('card_id')
        description = request.data.get('description', '')
        cvc = request.data.get('cvc')

        # Validate card_id
        if not card_id:
            return Response({'error': 'card_id is required'}, status=400)

        # Optionally validate cvc
        if cvc:
            if not cvc.isnumeric() or len(cvc) not in [3, 4]:
                return Response({'error': 'Invalid cvc'}, status=400)

        if user.is_client:
            get_provider = Provider.objects.filter(id=user.client.user_provider).first()
            stripe_account_id = get_provider.stripe_account_id
            customer_id = user.client.stripe_account.stripe_id
        elif user.is_provider:
            stripe_account_id = user.provider.stripe_account_id

        charge = stripe.Charge.create(
            amount=amount,
            currency='usd',
            customer=customer_id,
            transfer_data={'destination': stripe_account_id},
            source=card_id,
            description=description
        )
        create_client_payment(pk, price)
        update_paid_client_invoice(pk)

        return Response(charge, status=status.HTTP_201_CREATED)
    except stripe.error.StripeError as e:
        raise ValidationError({'error': e})


def create_client_payment(invoice_id, price_remain):
    ClientPayment.objects.create(
        invoice_id=invoice_id,
        price=price_remain,
        status=ClientPaymentType.STRIPE.value
    )


def update_paid_client_invoice(client_invoice_id):
    ClientInvoice.objects \
        .filter(id=client_invoice_id) \
        .update(status=ClientInvoiceStatus.PAID.value)
